package auleiy.halo.client;

import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.model.EntityModel;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.RenderLayerParent;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.joml.Quaternionf;
import top.theillusivec4.curios.api.SlotContext;
import top.theillusivec4.curios.api.client.ICurioRenderer;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@OnlyIn(Dist.CLIENT)
public class HaloRenderer implements ICurioRenderer {

    private final Halo Halo;

    public HaloRenderer(Halo halo) {
        Halo = halo;
    }

    private final Map<UUID, Vec2> LastRotations = new HashMap<>();

    @Override
    public <T extends LivingEntity, M extends EntityModel<T>> void render(ItemStack itemStack,
                                                                          SlotContext slotContext,
                                                                          PoseStack poseStack,
                                                                          RenderLayerParent<T, M> renderLayerParent,
                                                                          MultiBufferSource multiBufferSource,
                                                                          int light, float limbSwing,
                                                                          float limbSwingAmount,
                                                                          float deltaTicks,
                                                                          float ageInTicks,
                                                                          float netHeadYaw,
                                                                          float headPitch) {

        poseStack.pushPose();
        LivingEntity e = slotContext.entity();
        poseStack.rotateAround(YawPitchEulerToQuat(0, -e.yBodyRot), 0, 0, 0); // 将以身体为参照物转为以世界为参照物

        float x = e.xRotO;
        float y = e.yHeadRot;

        Vec2 lastRot = LastRotations.getOrDefault(e.getUUID(), new Vec2(x, y));
        float xr = lastRot.x;
        float yr = lastRot.y;

        if (lastRot.x != x || lastRot.y != y) {
                               // deltaTicks / 20 * 4
            xr = Mth.lerp(deltaTicks / 5, xr, x);
            yr = Mth.lerp(deltaTicks / 5, yr, y);
        }

        LastRotations.put(e.getUUID(), new Vec2(xr, yr));

        float t = ageInTicks * Mth.PI / 40;
        float intensity = (Mth.cos(t) + 1) * 0.1F + 0.8F;
        float yo = (Mth.sin(t) + 1) * 0.1F;
        poseStack.rotateAround(YawPitchEulerToQuat(xr, yr), 0, 0, 0); // 将以世界为参照物转为以头部为参照物
        Vec3 off = Halo.offset();
        poseStack.translate(0.5F - off.x, -0.6F - off.y - yo, -0.5F - off.z);
        poseStack.rotateAround(YawRollEulerToQuat(Halo.yaw(), Halo.roll()), 0, 0.6F, 0);

        VertexConsumer vc =
                multiBufferSource.getBuffer(Halo.renderType());

        Halo.model().render(
                poseStack,
                vc,
                0xF000F0,
                OverlayTexture.NO_OVERLAY,
                intensity, intensity, intensity, 1.0F
        );

        poseStack.popPose();
    }

    // 为只有head值而优化过的欧拉角转四元数
    Quaternionf YawPitchEulerToQuat(float y, float p) {
        float cr = Mth.cos(Mth.DEG_TO_RAD * y * 0.5f);
        float sr = Mth.sin(Mth.DEG_TO_RAD * y * 0.5f);
        float cp = Mth.cos(Mth.DEG_TO_RAD * p * 0.5f);
        float sp = Mth.sin(Mth.DEG_TO_RAD * p * 0.5f);
        return new Quaternionf(cp * sr, sp * cr, -sp * sr, cp * cr);
    }

    // 为光环特制的仅Yaw、Roll欧拉角转四元数
    // 以玩家视角为参照物时，实际的Roll是Yaw，实际的Yaw是Roll
    Quaternionf YawRollEulerToQuat(float y, float r) {
        float cy = Mth.cos(Mth.DEG_TO_RAD * r * 0.5f);
        float sy = Mth.sin(Mth.DEG_TO_RAD * r * 0.5f);
        float cr = Mth.cos(Mth.DEG_TO_RAD * -y * 0.5f); // Yaw更大的时候按照习惯应该是向后旋转
        float sr = Mth.sin(Mth.DEG_TO_RAD * -y * 0.5f);
        return new Quaternionf(cy * sr, sy * sr, sy * cr, cy * cr);
    }
}
